package com.itstyle.seckill.topic.jichu;

/**
 * @Auther: liuwenxiang
 * @Date: 2020/3/11 23:57
 * @Description:
 */
public class TestString {

    /**
     * 1.为什么string可以不用new对象就直接使用
         * java虚拟机处理基础类型与引用类型的方式是不一样的，
         * 对于基本类型，java虚拟机会为其分配数据类型实际占用的内存空间，
         * 而对于引用类型变量，他仅仅是一个指向堆区中某个实例的指针
        ================================
     *    分清"基本类型"和"引用类型"--
     *    基本类型：int dubble float char long boolean  byte（注意不包含string）
     *    --jvm为基本类型提供自动装箱操作，将其转为引用类型，这个时候使用就需要new对象
     *    引用类型: 对象
     *  ================================
     *    String a="abc"; --这种字符串存在字符串缓冲池中（方法区中）
     *    机制：先在缓冲池找，没有就生成一个(有就直接使用)
     *    String a = new String("tom"); --这种对象存在堆中
     *    机制：每次使用都新创建
     *
     *    所以单个字符串，建议使用String a="abc";方式，提高内存使用率。
     *
     *   ================================
     *
     */
    public static void main(String[] args) {

    }

    /**
     * 1. String str=new String("abc")和String str="abc"的字符串“abc”都是存放在堆中，而不是存在
     * 栈中。
     *  2. 其实在在java中有一个“字符数据池”的内存管理机制。
     *  3. String str="abc"，执行这句话时，会先去“字符数据池”搜索时候有“abc”这个字符串，如果有
     * ，则将字符串的首地址赋值给str，如果没有，生成一个新的字符串“abc”并且将首地址赋值给str；
     *  4. String str=new String("abc")，执行这句话时，不会考虑时候已经存在了“abc”这个字符串，而
     * 是直接生成一个新的字符串“abc”并将首地址赋值给str，注意“abc”并不放在“字符数据池”中；
     *  5. 由以上分析可知，String str="abc"和效率要高于String str=new String("abc")，因为如果有重复
     * 的字符串时，第一种方式可以节省空间。
     *  6. 下面举例说明一下，好好看看结果，仔细分析原因，上面已经说明的很清楚了：
     * public class Test{
     *  public static void main(String args[]){
     *   String s1=new String("abc");//直接在堆中生成新的“abc”
     *   String s2=new String("abc");//直接在堆中生成新的“abc”
     *   String s3="abc";//先去“字符数据池”搜索时候有“abc”这个字符串，如果有，则
     * 将字符串的首地址赋值给s3，如果没有，则在“字符数据池”中生成一个新的字符串“abc”并且将首地
     * 址赋值给s3；
     *   String s4="abc";//去“字符数据池”搜索时发现了上一步生成的“abc”这个字符串
     * ，把该字符串首地址赋值给s4，这时其实s3和s4指向同一个字符数据池中的“abc”
     *   System.out.println(s1==s2);
     *   System.out.println(s1==s3);
     *   System.out.println(s2==s3);
     *   System.out.println(s3==s4);
     *  }
     * }
     * 结果：
     * false
     * fasle
     * false
     * true
     *
     * 另外：例如：
     * String str1=”java”;    //指向字符串池
     * String str2=”blog”;   //指向字符串池
     *
     * String s=str1+str2;   //s是指向堆中值为"javablog"的对象，+运算符会在堆中建立来两个String对象，这两个对象的值分别是"java" "blog". 也就是说从字符串池中复制这两个值，然后在堆中创建两个对象，然后再建立对象s,然后将"javablog"的堆地址赋给s.    这句共创建了3个String 对象！
     * System.out.println(s==”javablog”);   //结果是false。
     * Jvm确实对型如String str1=”java”;的String对象放在常量池里，但是它是在编译时那么做的，而String s=str1+str2;是在运行时刻才能知道，也就是说str1+str2是在堆里创建的，所以结果为false了。
     * 如果改成一下两种方式：
     * String s="java" + "blog"; //直接将"javablog"放入字符串池中，System.out.println(s==”javablog”); 的结果为true， 这个句子创建了0个String对象
     * String s=str1+ "blog"; //不放入字符串池，而是在堆中分配,System.out.println(s==”javablog”); 的结果为False,    这个句子创建了2个String对象
     * 总结
     * 综上所述，创建字符串有两种方式：两种内存区域（pool,heap）
     * 1，" " 引号创建的字符串在字符串池中
     * 2，new，new创建字符串时首先查看池中是否有相同值的字符串，如果有，则拷贝一份到堆中，然后返回堆中的地址；如果池中没有，则在堆中创建一份，然后返回堆中的地址（注意，此时不需要从堆中复制到池中，否则，将使得堆中的字符串永远是池中的子集，导致浪费池的空间）！
     *
     * 另外，对字符串进行赋值时，如果右操作数含有一个或一个以上的字符串引用时，则在堆中再建立一个字符串对象，返回引用；如String s=str1+ "blog";
     */
}
